package com.aSemy.qotwReader.core.question;

import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;

import javax.imageio.ImageIO;

import com.aSemy.qotwReader.core.types.EbookType;
import com.aSemy.qotwReader.core.utils.Filenames;



import net.htmlparser.jericho.*;

/**
 * A class for organising data to do with saving the HTML source code of the question, and also images.
 * @author Adam Semenenko
 */
public class QuestionFile
{
    /** The HTML Source code of the question. */
    final private Source questionSource;
    /** Where the HTML source should be saved. */
    private OutputDocument questionOutputSource;
    /** Metadata about the question. (Title, date, etc.) */
    final private QuestionData metadata;
    /** Where the html source code should be saved. */
    final private File outputFile;
    
    /**
     * Create an object for saving the question HTML to file.
     * When this object is created images are downloaded and saved, as well as the question HTML (contained in the QuestionHTML argument).
     * @param html The QuestionHTML object for this question.
     * @param metadata The previously gathered metadata for this question.
     * @throws IOException If the question HTML or images could not be saved to file.
     */
    public QuestionFile(QuestionHTML html, QuestionData metadata) throws IOException
    {
        this.questionSource = html.getQuestionSource();
        this.questionOutputSource = new OutputDocument(questionSource);
        this.metadata = metadata;
        
        this.outputFile = new File(Filenames.getFilename(EbookType.html, metadata));
        
        saveToFile();
        /* TODO what want to actually do is to try
         * and open the file if it exists use it,
         * don't need to save it. */
    }
    
    /**
     * Save the question to file.
     * @throws IOException If the source could not be written.
     */
    private void saveToFile() throws IOException
    {
        saveImages();

        writeSourceToFile();
    }
    
    /**
     * Write the source of the question ({@link #questionSource}) to file ({@link #questionOutputSource}).
     * @return Return the file the question is saved to.
     * @throws IOException If the file be written.
     */
    private File writeSourceToFile() throws IOException
    {
        FileWriter fileWriter = new FileWriter(outputFile);
        BufferedWriter htmlOut = new BufferedWriter(fileWriter);
        // write the html to file
        htmlOut.write(questionOutputSource.toString());
        
        htmlOut.close();
        
        return outputFile;
    }
    
    /**
     * Download all images used in a question
     * Need to save the images to file and change the source to point to the locally saved files.
     * @param questionTitle The title of the question these images are being downloaded from.
     */
    private void saveImages()
    {
        // get all image tags
        for (Element e : questionSource.getAllElements(HTMLElementName.IMG))
        {
            // get the image location
            final String sourceImageURL = e.getAttributeValue("src");
            
            if (sourceImageURL != null)
            {
                String localLocationToSave;
                String imageURL;
                                
                // if it starts with / it's a relative image.
                if (sourceImageURL.startsWith("/"))
                {
                    // need to save it in the image folder, if not there already.
                    imageURL = Filenames.b3taAddress + sourceImageURL;
                    
                    // remove the first slash, otherwise it prints to the hard drive, not relative.
                    localLocationToSave = (String) sourceImageURL.subSequence(1, sourceImageURL.length());
                }
                // if it starts with http it's an external image
                else if (sourceImageURL.startsWith("http://"))
                {
                    // get the image name. Save it to /image/questiontitle/imagename.jpg
                    
                    String[] split = sourceImageURL.split("[*/*]|[*=*]"); // split around forwards slashes or equals
                    localLocationToSave =
                          "images"
                        + File.separator + metadata.getFilesafeTitle()
                        + File.separator + split[split.length - 1];
                    imageURL = sourceImageURL;
                    
                }
                else // don't know what we're dealing with, ignore this image, do not save
                    continue;
                
                // replace the file separators with the local verison.
                localLocationToSave = localLocationToSave.replace('/', File.separatorChar);
                
                // update the source to point to the new file location - not the image on the internet.
                String elementSource = e.toString();
                elementSource = elementSource.replace(sourceImageURL, localLocationToSave);
                questionOutputSource.replace(e.getBegin(), e.getEnd(), elementSource);

                // save the image at imageURL to localLocationToSave
                saveImageToFile(imageURL, localLocationToSave);
            }
        }
    }
    
    /**
     * Save an image to a file. If the image URL has a folder then it's saved to a folder in {@link #outputFile}.
     * <br>
     * If an image can't be downloaded (404 etc) or saved this is dealt with internally and does not interrupt the conversion process.
     * @param imageURL The URL of the image from the source code.
     * @param localLocationToSave The parent directory where the question HTML is being saved. This is so images with relative pathnames can be saved inside.
     */
    private void saveImageToFile(String imageURL, String localLocationToSave)
    {
        try
        {
            final URL url = new URL(imageURL);
            
            final BufferedImage image = ImageIO.read(url);
                        
            if (image == null)
            {
                System.out.println("Image could not be read from URL '" + url.toString() + "'. Skipping saving image");
                return;
            }
            
            File imageFile = new File(outputFile.getParent(), localLocationToSave);
            
            // make the parent directories to save the image into
            imageFile.getParentFile().mkdirs();
            
            boolean fileCreated = imageFile.createNewFile();
            
            if (fileCreated == true) // named file sucessfully created, it did not previously exist
            {
                String[] findFullStop = imageURL.split("\\."); // this is regex for a full stop         
                String imageFiletype = findFullStop[findFullStop.length - 1]; // get the last element - it's the filetype
                
                ImageIO.write(image, imageFiletype, imageFile);
            }
            else
                return; // named file already exists or could not be created
        }
        catch (MalformedURLException e)
        {
            System.out.println("Tried saving image, but could not read URL. Skipping saving image.");
            e.printStackTrace();
        }
        catch (IOException e)
        {
            if (e.getCause() != null && e.getCause().getClass().equals(UnknownHostException.class))
            {
                System.out.println("Could not download the image " + imageURL);
                System.out.println("Unknown host exception (Might be a 404?)");
                return;
                
            }
            System.out.println("Error saving file to disk.");
            System.out.println("Image url: " + imageURL);
            e.printStackTrace();
        }
    }

    /**
     * @return Get the File where the HTML source code is saved.
     */
    public File getOutputFile() { return outputFile; }
}
